home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / IFC_112 / netscape / application / FoundationApplet.java < prev    next >
Encoding:
Text File  |  1999-05-28  |  13.6 KB  |  392 lines  |  [TEXT/CWIE]

  1. // FoundationApplet.java
  2. // By Ned Etcode
  3. // Copyright 1995, 1996, 1997 Netscape Communications Corp.  All rights reserved.
  4.  
  5. package netscape.application;
  6.  
  7. import netscape.util.*;
  8.  
  9. import java.applet.Applet;
  10.  
  11. /** java.applet.Applet subclass that attaches a FoundationPanel instance
  12.   * to the Java Applet. Each Application has a FoundationApplet
  13.   * instance, although you will never access it directly.
  14.   * @note 1.1 releasing application reference in destroy()
  15.   */
  16. public class FoundationApplet extends Applet implements Runnable {
  17.     static Hashtable            groupToApplet = new Hashtable(1);
  18.     Application                 application;
  19.     FoundationPanel             panel;
  20.     boolean                     startedRun, appletStarted;
  21.     private static Vector       applicationStack;   /// ddk - ADDED FOR JAVASCRIPT SUPPORT
  22.  
  23.     /** Constructs a new FoundationApplet. */
  24.     public FoundationApplet() {
  25.         super();
  26.     }
  27.  
  28.     static void setAppletForGroup(FoundationApplet applet) {
  29.         groupToApplet.put(Thread.currentThread().getThreadGroup(), applet);
  30.     }
  31.  
  32.     static FoundationApplet applet() {
  33.         ThreadGroup group = Thread.currentThread().getThreadGroup();
  34.  
  35.         return (FoundationApplet)groupToApplet.get(group);
  36.     }
  37.  
  38.     /** Sets the Applet's Application.
  39.       */
  40.     public void setApplication(Application application) {
  41.         this.application = application;
  42.     }
  43.  
  44.     /** Returns the Applet's Application.
  45.       * @see #setApplication
  46.       */
  47.     public Application application() {
  48.         return application;
  49.     }
  50.  
  51.     /** Initializes the FoundationApplet instance. Also creates the
  52.       * Application object and starts a new thread for it to run in. You
  53.       * should never call this method.
  54.       */
  55.     public void init() {
  56.         Thread appThread = new Thread(this, "Main Application Thread");
  57.  
  58.         super.init();
  59.         setAppletForGroup(this);
  60.         // This lock is used to make sure that we don't return before the
  61.         // application is set up enough to allow the processing of AWT events
  62.         // that come in to the applet frame.  run() unlocks it.
  63.         appThread.start();
  64.         synchronized (this) {
  65.             while (!startedRun) {
  66.                 try {
  67.                     wait();
  68.                 }
  69.                 catch (InterruptedException e) {
  70.                 }
  71.             }
  72.         }
  73.     }
  74.  
  75.     /** Creates the Application in the main Application thread.
  76.       * You should never call this method.
  77.       */
  78.     public void run() {
  79.         String param = getParameter("ApplicationClass");
  80.  
  81.         if (param != null && !param.equals("")) {
  82.             Object newObject = instantiateObjectOfClass(param);
  83.  
  84.             if (newObject instanceof Application) {
  85.                 application = (Application)newObject;
  86.             } else {
  87.                 throw new InconsistencyException("ApplicationClass " + param +
  88.             " must be a subclass of netscape.application.Application");
  89.             }
  90.         } else {
  91.             throw new InconsistencyException("An ApplicationClass parameter must be specified in the <applet> tag.  For example:\n<applet code=\"netscape.application.FoundationApplet\" width=320 height=200>\n    <param name=\"ApplicationClass\" value=\"MyApplication\">\n</applet>\n");
  92.         }
  93.         synchronized (this) {
  94.             startedRun = true;
  95.             // This notify will cause the applet's init routine to return.
  96.             notifyAll();
  97.             // We don't run the event loop until the start() comes in.
  98.             // This means we can draw to the applet's Graphics context.
  99.             while (!appletStarted) {
  100.                 try {
  101.                     wait();
  102.                 } catch (InterruptedException e) {
  103.                 }
  104.             }
  105.         }
  106.         application.run();
  107.     }
  108.  
  109.     /** Starts the Applet. */
  110.     public void start() {
  111.         synchronized (this) {
  112.             ApplicationEvent event = new ApplicationEvent();
  113.  
  114.             if (!appletStarted) {
  115.                 // If this is the first start for the applet, unlock the
  116.                 // run() call.
  117.                 appletStarted = true;
  118.                 notifyAll();
  119.             }
  120.             event.type = ApplicationEvent.APPLET_STARTED;
  121.             event.processor = application;
  122.             application.eventLoop.addEvent(event);
  123.         }
  124.     }
  125.  
  126.     /** Stops the Applet. */
  127.     public void stop() {
  128.         ApplicationEvent event = new ApplicationEvent();
  129.  
  130.         event.type = ApplicationEvent.APPLET_STOPPED;
  131.         event.processor = application;
  132.         application.eventLoop.addEvent(event);
  133.     }
  134.  
  135.     /** Destroys the Applet. */
  136.     public void destroy() {
  137.         /* AWT Thread */
  138.         application.stopRunningForAWT();
  139.         super.destroy();
  140.     }
  141.  
  142.     void destroyFromIFC() {
  143.         super.destroy();
  144.     }
  145.  
  146.     /** Cleanup resources associated with the Applet.
  147.       * this is always called by the ifc main thread
  148.       */
  149.     void cleanup() {
  150.         // It would be nice to be able to post some application cleanup
  151.         // notification to interested parties here.  ALERT!
  152.         Enumeration groups;
  153.         FoundationApplet        applet;
  154.         ThreadGroup             group;
  155.  
  156.         /* it would be nice to be able to post some application destroy
  157.          * notification to interested parties here.  ALERT!
  158.          */
  159.         groups = groupToApplet.keys();
  160.  
  161.         removeApplication(application); /// ddk - ADDED FOR JAVASCRIPT SUPPORT
  162.  
  163.         while (groups.hasMoreElements()) {
  164.             group = (ThreadGroup)groups.nextElement();
  165.             applet = (FoundationApplet)groupToApplet.get(group);
  166.  
  167.             if (applet == this) {
  168.                 groupToApplet.remove(group);
  169.                 break;
  170.             }
  171.         }
  172.         application = null;
  173.  
  174.     }
  175.  
  176.     /* Installs the FoundationCanvas in the Applet with the necessary
  177.      * RootView.
  178.      */
  179.     void setupCanvas(Application app) {
  180.         int width, height;
  181.         RootView rootView;
  182.  
  183.         application = app;
  184.         width = size().width;
  185.         height = size().height;
  186.         panel = createPanel();
  187.         application.setMainRootView(panel.rootView());
  188.  
  189.         panel.reshape(0, 0, width, height);
  190.         add(panel);
  191.  
  192.         // Eventually we will support using a custom view as an alternative
  193.         // to a custom application. Place a custom view (if specified) on the
  194.         // rootView for the user.
  195.         // if (defaultView != null) {
  196.         //     defaultView.init(0, 0, width, height);
  197.         //     rootView.addSubview(defaultView);
  198.         // }
  199.  
  200.         // Eventually we will want to load an interface file here.  ALERT!
  201.         // loadInterface(getParameter("velocity"));
  202.     }
  203.  
  204.     /** Overridden to properly layout the Applet. */
  205.     public void layout() {
  206.         if (panel != null) {
  207.             java.awt.Dimension size = size();
  208.             java.awt.Insets insets = insets();
  209.             int x = insets.left, y = insets.top,
  210.                 w = size.width - (insets.left + insets.right),
  211.                 h = size.height - (insets.top + insets.bottom);
  212.  
  213.             if (w > 0 && h > 0) {
  214.                 panel.reshape(x, y, w, h);
  215.             }
  216.         }
  217.     }
  218.  
  219.     Object instantiateObjectOfClass(String className) {
  220.         Class newClass;
  221.         Object newObject;
  222.  
  223.         try {
  224.             newClass = classForName(className);
  225.             newObject = newClass.newInstance();
  226.         } catch (ClassNotFoundException e) {
  227.             throw new InconsistencyException("Unable to find class \"" + className + "\"");
  228.         } catch (InstantiationException e) {
  229.             throw new InconsistencyException("Unable to instantiate class \"" + className + "\" -- " + e.getMessage());
  230.         } catch (IllegalAccessException e) {
  231.             throw new InconsistencyException("Unable to instantiate class \"" + className + "\" -- " + e.getMessage());
  232.         }
  233.  
  234.         return newObject;
  235.     }
  236.  
  237.     /** This method must be implemented by the Applet developer because
  238.       * there is no way in the standard Java API for system classes (such as,
  239.       * netscape.application) to look up an Applet's class by name. The
  240.       * static method <b>Class.forName()</b> simply looks up one level in the
  241.       * stack and gets the ClassLoader associated with the method block of the
  242.       * caller. When the netscape.application classes are installed as
  243.       * system classes, the ClassLoader is <b>null</b>. Thus, when code in
  244.       * netscape.application calls <b>Class.forName()</b> it can only find
  245.       * other system classes.<p>
  246.       * The solution is an API that allows code to
  247.       * find the ClassLoader for an applet by URL, and public API on
  248.       * ClassLoader to ask it to load classes by name. Until these
  249.       * enhancements can be made and distributed to all the world's Java
  250.       * systems, Applets must subclass FoundationApplet and
  251.       * implement the following one-line method:
  252.       * <pre>
  253.       *     public abstract Class classForName(String className)
  254.       *         throws ClassNotFoundException {
  255.       *         return Class.forName(className);
  256.       *     }
  257.       * </pre>
  258.       */
  259.     public Class classForName(String className)
  260.         throws ClassNotFoundException {
  261.         return Class.forName(className);
  262.     }
  263.  
  264.     /** @private */
  265.     public void paint(java.awt.Graphics g) {
  266.         super.paint(g);
  267.     }
  268.  
  269.     /** Creates and returns the Applet's FoundationPanel.
  270.       * FoundationApplet subclasses can override this method to provide a
  271.       * custom FoundationPanel subclass.
  272.       * @see FoundationPanel
  273.       */
  274.     protected FoundationPanel createPanel() {
  275.         return new FoundationPanel();
  276.     }
  277.  
  278.     /** Returns the FoundationPanel the Applet is using to display its
  279.       * RootView.
  280.       */
  281.     public FoundationPanel panel() {
  282.         return panel;
  283.     }
  284.  
  285.     /* This method will try to figure out if we are running in the Mozilla
  286.      * thread.  These values are valid for the Nav3.0/NavGold3.0 products.
  287.      * Names appear valid on Sun and NT. This is also called in the EventLoop
  288.      * before trying to setPriority to the thread.
  289.      *
  290.      * This method was removed to attempt to allow IE to call IFC stuff
  291.      * properly. - ddk
  292.      */
  293.     static boolean isMozillaThread(Thread aThread)  {   /// ddk - ADDED FOR JAVASCRIPT SUPPORT
  294. //        ThreadGroup aThreadG = aThread.getThreadGroup();
  295. //
  296. //        return (aThread.getName().equals("main")
  297. //                && aThreadG.getName().equals("main")
  298. //                && aThreadG.getParent().getName().equals("system")
  299. //                && aThreadG.getParent().getParent() == null);
  300. //
  301.         return true;
  302.     }
  303.  
  304.     /** Any JavaScript function that sends message to an IFC-based Applet must
  305.       * call this method before sending any messages. Returns the Application.
  306.       * The JavaScript function must generate a corresponding
  307.       * <b>popIFCContext()</b> call.
  308.       * This method places the Application object on a stack, so the IFC can
  309.       * properly determine
  310.       * which Application is running when the JavaScript method executes.
  311.       * Failure to call <b>popIFCContext()</b> after the JavaScript finishes
  312.       * may result in the Application not being properly garbage collected.
  313.       * Here's a simple JavaScript example:
  314.       * <PRE>
  315.       *  <SCRIPT>
  316.       *   function sendToFront() {
  317.       *     SimpleDrawApp = document.applets[0].pushIFCContext();
  318.       *     SimpleDrawApp.drawController.moveToFront();
  319.       *     document.applets[0].popIFCContext();
  320.       *   }
  321.       *  </SCRIPT>
  322.       * </PRE>
  323.       * <i><b>Note:</b> This method can only be called from JavaScript
  324.       * code.</i>
  325.       * @see #popIFCContext
  326.       */
  327.     public Application pushIFCContext()   {  /// ddk - ADDED FOR JAVASCRIPT SUPPORT
  328.         if(application == null) {
  329.             return null;
  330.         }
  331.  
  332.         if(!isMozillaThread(Thread.currentThread()))    {
  333.             throw new InconsistencyException(
  334.                         "pushIFCContext() must be called from JavaScript.");
  335.         }
  336.  
  337.         if(applicationStack == null)    {
  338.            applicationStack = new Vector();
  339.         }
  340.  
  341.         applicationStack.addElement(application);
  342.         return application;
  343.     }
  344.  
  345.     /** Any JavaScript function that sends message to an IFC-based Applet must
  346.       * call this method after sending all messages, to match the previous
  347.       * <b>pushIFCContext()</b> call.<p>
  348.       * <i><b>Note:</b> This method can only be called from JavaScript
  349.       * code.</i>
  350.       * @see #pushIFCContext
  351.       */
  352.     public void popIFCContext()   {    /// ddk - ADDED FOR JAVASCRIPT SUPPORT
  353.  
  354.         if(!isMozillaThread(Thread.currentThread()))    {
  355.             throw new InconsistencyException(
  356.                         "popIFCContext() must be called from JavaScript.");
  357.         }
  358.  
  359.         if(applicationStack == null)    {
  360.             throw new InconsistencyException(
  361.             "popIFCContext() called without ever calling pushIFCContext()");
  362.         }
  363.  
  364.         if(applicationStack.lastElement() != application)   {
  365.             throw new InconsistencyException("popIFCContext() attempted to pop " + applicationStack.lastElement() + " which was not itself:" + application);
  366.         }
  367.  
  368.         if(applicationStack.removeLastElement() == null)    {
  369.             throw new InconsistencyException("extraneous popIFCContext() called without corresponding pushIFCContext()");
  370.         }
  371.     }
  372.  
  373.     static Application currentApplication() {   /// ddk - ADDED FOR JAVASCRIPT SUPPORT
  374.         if(applicationStack == null)    {
  375.            return null;
  376.         }
  377.  
  378.         return (Application)applicationStack.lastElement();
  379.     }
  380.  
  381.     static void removeApplication(Application app) {   /// ddk - ADDED FOR JAVASCRIPT SUPPORT
  382.         if(applicationStack == null)    {
  383.            return;
  384.         }
  385.  
  386.         if(app == null) {
  387.             return;
  388.         }
  389.         applicationStack.removeAll((Object)app);
  390.     }
  391. }
  392.